﻿using MiniFox.Caching;
using MiniFox.Components;
using MiniFox.Platform.Exceptions;
using MiniFox.Platform.Models;
using MiniFox.Platform.OAuth2.Configurations;
using MiniFox.Platform.OAuth2.Providers;

namespace MiniFox.Platform.OAuth2.Services
{
    /// <summary>
    /// 授权令牌管理(后台服务)
    /// </summary>
    [AutoResolve]
    public class AccessTokenService : Component, IAccessTokenService
    {
        /// <summary>
        /// 
        /// </summary>
        public AccessTokenService()
        {

        }
        /// <summary>
        /// 
        /// </summary>
        [AutoWired]
        protected IOAuth2ConfigProvider ConfigProvider
        {
            get;
            set;
        }
        /// <summary>
        /// 
        /// </summary>
        [AutoWired]
        protected virtual IAccessTokenProvider Provider
        {
            get;
            set;
        }
        /// <summary>
        /// 
        /// </summary>
        public AccessTokenConfiguration Configuration
        {
            get
            {
                return this.ConfigProvider.AccessTokenConfiguration;
            }
        }
        /// <summary>
        /// 
        /// </summary>
        protected internal virtual CacheProvider Cache
        {
            get
            {
                return CacheService.DefaultCachingProvider;
            }
        }

        /// <summary>
        /// 客户端通过授权码提取授权令牌
        /// </summary>
        /// <param name="appId"></param>
        /// <param name="secretKey"></param>
        /// <param name="authCode"></param>
        /// <returns></returns>
        public AuthorizeToken CreateAuthorizeToken(string appId, string secretKey, string authCode)
        {
            if (!this.Provider.VerifyClient(appId, secretKey))
            {
                throw new PlatformException("ERR_UnknownClientApp");
            }

            if (!this.Provider.VerifyAuthCode(appId, authCode))
            {
                throw new PlatformException("ERR_InvalidAuthCode");
            }
            AuthorizeToken token = this.Provider.CreateAuthorizeToken(appId, authCode, this.Configuration.AccessTokenExpires, this.Configuration.RenewTokenExpires);
            return token;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="appId"></param>
        /// <param name="secretKey"></param>
        /// <param name="refreshToken"></param>
        /// <returns></returns>
        public AuthorizeToken RenewAuthorizeToken(string appId, string secretKey, string refreshToken)
        {
            if (!this.Provider.VerifyClient(appId, secretKey))
            {
                throw new PlatformException("ERR_UnknownClientApp");
            }

            if (!this.Provider.VerifyRenewToken(appId, refreshToken))//刷新令牌未过期
            {
                return null;
            }
            AuthorizeToken token = this.Provider.GetAuthorizeToken(appId, refreshToken, this.Configuration.AccessTokenExpires, this.Configuration.RenewTokenExpires, true);
            return token;
        }


        #region 获取身份
        /// <summary>
        /// 
        /// </summary>
        /// <param name="accessToken"></param>
        /// <returns></returns>
        public virtual OpenAuthIdentity GetIdentity(string accessToken)
        {
            if (accessToken == null)
            {
                throw new PlatformException("ERR_InvalidAccessToken", accessToken);
            }
            AuthorizeToken authorizeToken = Cache.Get(accessToken, () =>
            {
                AuthorizeToken token = this.Provider.GetAuthorizeToken(accessToken);
                return token;
            }, this.Configuration.CacheDuration);
            if (authorizeToken.AccessTokenExpired())
            {
                Cache.Remove(accessToken);
                throw new PlatformException("ERR_AccessTokenExpired", accessToken);
            }
            var identity = this.Provider.GetIdentity(accessToken, Enum.Parse<AuthScope>(authorizeToken.Scope));
            if (identity == null)
            {
                throw new PlatformException("ERR_InvalidAccessToken", accessToken);
            }
            return identity;
        }

        #endregion
    }
}
